package com.yanqu.road.server.manager.activity.hsisland.rank;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;

public class CrossHsIslandRankListModel {

    private final int rankMaxNum; // 最大排名数量

    private final Comparator<HsIslandRank> rankSort;

    private final Map<String, HsIslandRank> rankMap = new ConcurrentHashMap<>();

    private final AtomicBoolean needSort = new AtomicBoolean(false);

    private final ReadWriteLock rwLock = new ReentrantReadWriteLock();


    private List<HsIslandRank> sortedRankList = Collections.synchronizedList(new ArrayList<>());

    private Map<String, Integer> userRankMap = new ConcurrentHashMap<>();

    public CrossHsIslandRankListModel() {
        this.rankMaxNum = Integer.MAX_VALUE;
        this.rankSort = new HsIslandRankSort();
    }

    public CrossHsIslandRankListModel(Comparator<HsIslandRank> rankSort) {
        this.rankMaxNum = Integer.MAX_VALUE;
        this.rankSort = rankSort;
    }

    public CrossHsIslandRankListModel(int rankMaxNum, Comparator<HsIslandRank> rankSort) {
        this.rankMaxNum = rankMaxNum;
        this.rankSort = rankSort;
    }

    /**
     * 更新排名
     */
    private void updateRank(HsIslandRank rank) {
        if (rankMap.containsKey(rank.getRankId())) {
            HsIslandRank existingRank = rankMap.get(rank.getRankId());
            existingRank.setValue(rank.getValue());
            existingRank.setParam(rank.getParam());
            existingRank.setLastUpdateTime(rank.getLastUpdateTime());
        } else {
            rankMap.put(rank.getRankId(), rank);
        }
    }

    public void rankChange(HsIslandRank rank) {
        rwLock.writeLock().lock();
        try {
            updateRank(rank);
            needSort.set(true); // 标记需要排序
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public void batchRankChange(List<HsIslandRank> ranks) {
        rwLock.writeLock().lock();
        try {
            for (HsIslandRank rank : ranks) {
                updateRank(rank);
            }
            needSort.set(true); // 标记需要排序
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public List<HsIslandRank> getRankList() {
        // 首先获取读锁
        rwLock.readLock().lock();
        try {
            // 如果需要排序，则尝试获取写锁进行排序
            if (needSort.get()) {
                // 释放读锁之前检查一次需要排序的标志
                // 以避免在释放读锁和获取写锁之间的窗口期内错过排序的需要
                rwLock.readLock().unlock();
                rwLock.writeLock().lock();
                try {
                    // 检查其他线程是否已经完成了排序
                    if (needSort.get()) {
                        rebuildSortedRankList();
                        // 排序完成后，重置排序标志
                        needSort.set(false);
                    }
                } finally {
                    // 获取读锁前先释放写锁，实现锁降级
                    // 在释放写锁之后立即获取读锁，继续保护数据状态
                    rwLock.readLock().lock();
                    rwLock.writeLock().unlock();
                }
            }
            // 返回不可修改的视图
            return Collections.unmodifiableList(sortedRankList);
        } finally {
            // 无论如何都应该释放读锁
            rwLock.readLock().unlock();
        }
    }

    private void rebuildSortedRankList() {
        List<HsIslandRank> newSortedRankList = rankMap.values().parallelStream()
                .sorted(rankSort)
                .limit(rankMaxNum) // 仅获取排名最高的rankMaxNum个排名
                .collect(Collectors.toList());

        Map<String, Integer> newUserRankMap = new ConcurrentHashMap<>(newSortedRankList.size());
        for (int i = 0; i < newSortedRankList.size(); i++) {
            newUserRankMap.put(newSortedRankList.get(i).getRankId(), i + 1);
        }

        sortedRankList = newSortedRankList;
        userRankMap = newUserRankMap;
    }

    public int getMyRank(String rankId) {
        rwLock.readLock().lock();
        try {
            if (needSort.compareAndSet(true, false)) {
                rebuildSortedRankList();
            }
            return userRankMap.getOrDefault(rankId, -1);
        } finally {
            rwLock.readLock().unlock();
        }
    }

    public HsIslandRank getMyRankInfo(String rankId) {
        return rankMap.get(rankId);
    }

    public int getRankMaxNum() {
        return rankMaxNum;
    }
}
